package org.bbl.db.mybatis.mysql;

import org.apache.ibatis.session.SqlSession;
import org.bbl.db.domain.Language;
import org.bbl.db.domain.SearchResult;
import org.bbl.db.domain.WordSpell;
import org.bbl.db.mybatis.mapper.SearchResultMapper;
import org.bbl.db.mybatis.mapper.WordSpellMapper;
import org.bbl.utils.GeezUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author biniam.gebremichael
 * @since 2/21/13
 */
public class SearchResolver {
    MyEntityResolver entityResolver;
    Language language;
    int bookIdStart, bookIdEnd;
    String key;

    private final Map<String, List<SearchResult>> searchResult = new HashMap<String, List<SearchResult>>();
    private final ConcurrentMap<Integer, Boolean> found = new ConcurrentHashMap<Integer, Boolean>();

    final ConcurrentMap<String, List<Integer>> resultIds = new ConcurrentHashMap<String, List<Integer>>();

    public SearchResolver(MyEntityResolver entityResolver, Language language, int bookIdStart, int bookIdEnd, String key) {
        this.entityResolver = entityResolver;
        this.language = language;
        this.bookIdStart = bookIdStart;
        this.bookIdEnd = bookIdEnd;
        this.key = key;
    }

    public Map<String, List<SearchResult>> search() {
        final String mainTable = language.getShortName() + "_bible";

        searchTable(key, mainTable);

        if (language.isGeezFamily()) {

            WordSpell wordSpell = entityResolver.findByIdentifier(WordSpellMapper.class, language.getLanguageId(), key);
            if (wordSpell != null && wordSpell.getRoot() != null) {
                List<WordSpell> mySibling = entityResolver.findMySibling(WordSpellMapper.class, language.getLanguageId(), wordSpell.getRoot());
                for (WordSpell spell : mySibling) {
                    searchTable(spell.getWord(), mainTable);
                }
            } else {
                final String sera = GeezUtil.toSeraNoVowelYesI(key);
                final String seraTable = language.getShortName() + "v_bible";
                searchTable(sera, seraTable);
            }
        }
        convertIdToSearchResult(mainTable);
        return searchResult;
    }

    private void convertIdToSearchResult(String mainTable) {
        for (Map.Entry<String, List<Integer>> entry : resultIds.entrySet()) {
            if (!entry.getValue().isEmpty())
                searchResult.put(entry.getKey(), findAll(mainTable, entry.getValue()));
        }
    }

    private void searchTable(String key, String table) {
//        final String key1b = "% " + key + " %";
//        resultIds.put(key1b, search(table, key1b));
//
//        final String key2b = "%" + key + " %";
//        resultIds.put(key2b, search(table, key2b));

        final String key3b = "%" + key + "%";
        resultIds.put(key3b, search(table, key3b));
    }

    private List<Integer> search(String tableName, String key) {
        final List<Integer> raw = entityResolver.search(tableName, bookIdStart, bookIdEnd, language.getLanguageId(), key);
        final List<Integer> re = new ArrayList<Integer>();
        for (Integer i : raw) {
            if (found.putIfAbsent(i, true) == null) {
                re.add(i);
            }
        }
        return re;
    }

    private List<SearchResult> findAll(String tableName, List<Integer> ids) {
        final SqlSession session = ((MyEntityResolverImpl) entityResolver).getDataSource().getSession();
        try {
            SearchResultMapper mapper = session.getMapper(SearchResultMapper.class);
            List<SearchResult> list = new ArrayList<SearchResult>();
            for (Integer id : ids) {
                list.addAll(mapper.findById(tableName, language.getLanguageId(), id));
            }
            return list;
        } finally {
            session.close();
        }
    }

//
//    private List<SearchResult> findAll(String tableName, List<Integer> ids) {
//        final SqlSession session = ((MyEntityResolverImpl) entityResolver).getDataSource().getSession();
//        try {
//            SearchResultMapper mapper = session.getMapper(SearchResultMapper.class);
//            return mapper.findById(tableName, language.getLanguageId(), toList(ids));
//        } finally {
//            session.close();
//        }
//    }

    private String toList(List<?> l) {
        StringBuilder stringBuilder = new StringBuilder();
        if (l.size() == 0) {
            return "";
        }
        int i;
        for (i = 0; i < l.size() - 1; i++) {
            stringBuilder.append(l.get(i));
            stringBuilder.append(",");
        }
        stringBuilder.append(l.get(i));
        return stringBuilder.toString();
    }


}
